package store

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"gin-epg/internal/app/dao"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

// LocalStoreService 本地存储服务结构体
type LocalStoreService struct {
	rootPath string
}

// NewLocalStoreService 创建一个新的本地存储服务实例
func NewLocalStoreService() (*LocalStoreService, error) {
	if dao.RootPath == "" {
		return nil, fmt.Errorf("本地存储 RootPath 未初始化")
	}
	rootPath := dao.RootPath
	// 确保根目录存在
	err := os.MkdirAll(rootPath, os.ModePerm)
	if err != nil {
		return nil, err
	}

	return &LocalStoreService{
		rootPath: rootPath,
	}, nil
}

// Save 保存数据到本地
func (s *LocalStoreService) Save(key string, data []byte) error {
	filePath := filepath.Join(s.rootPath, key)
	return ioutil.WriteFile(filePath, data, os.ModePerm)
}

// SaveString 保存字符串数据到本地
func (s *LocalStoreService) SaveString(key string, data string) error {
	filePath := filepath.Join(s.rootPath, key)
	return ioutil.WriteFile(filePath, []byte(data), os.ModePerm)
}

// SaveKeyGz 压缩并保存数据到本地
func (s *LocalStoreService) SaveKeyGz(key string) error {
	// 定义本地临时目录
	tempDir := os.TempDir()
	// 定义本地未压缩文件路径
	localFilePath := filepath.Join(tempDir, key)
	// 定义本地压缩文件路径
	compressedFilePath := localFilePath + ".gz"

	// 从本地下载文件到临时目录
	if err := s.downloadToFile(key, localFilePath); err != nil {
		return fmt.Errorf("failed to download file: %v", err)
	}

	// 压缩文件
	if err := s.compressFile(localFilePath, compressedFilePath); err != nil {
		return fmt.Errorf("failed to compress file: %v", err)
	}

	// 上传压缩后的文件到本地
	if err := s.uploadFileToLocal(compressedFilePath, key+".gz"); err != nil {
		return fmt.Errorf("failed to upload compressed file: %v", err)
	}

	// 清理本地临时文件
	if err := s.cleanupFiles([]string{localFilePath, compressedFilePath}); err != nil {
		return fmt.Errorf("failed to clean up files: %v", err)
	}

	fmt.Printf("File %s has been compressed and saved locally as %s.gz\n", key, key)
	return nil
}

// ListDirectory 列出指定目录下的文件和文件夹
func (s *LocalStoreService) ListDirectory(prefix string) ([]FileInfo, error) {
	dirPath := filepath.Join(s.rootPath, prefix)
	fileInfos, err := ioutil.ReadDir(dirPath)
	if err != nil {
		return nil, err
	}

	var result []FileInfo
	for _, fileInfo := range fileInfos {
		result = append(result, FileInfo{
			Name:  fileInfo.Name(),
			IsDir: fileInfo.IsDir(),
		})
	}

	return result, nil
}

// DownloadToFile 从本地下载文件到临时目录
func (s *LocalStoreService) DownloadToFile(key, localFilePath string) error {
	sourceFilePath := filepath.Join(s.rootPath, key)
	return copyFile(sourceFilePath, localFilePath)
}

// downloadToFile 从本地下载文件到临时目录
func (s *LocalStoreService) downloadToFile(key, localFilePath string) error {
	sourceFilePath := filepath.Join(s.rootPath, key)
	return copyFile(sourceFilePath, localFilePath)
}

// compressFile 压缩文件
func (s *LocalStoreService) compressFile(src, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dstFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	gz := gzip.NewWriter(dstFile)
	defer gz.Close()

	_, err = io.Copy(gz, srcFile)
	return err
}

// uploadFileToLocal 上传文件到本地
func (s *LocalStoreService) uploadFileToLocal(localFilePath, key string) error {
	destinationFilePath := filepath.Join(s.rootPath, key)
	return copyFile(localFilePath, destinationFilePath)
}

// cleanupFiles 清理本地临时文件
func (s *LocalStoreService) cleanupFiles(files []string) error {
	for _, file := range files {
		if err := os.Remove(file); err != nil {
			return err
		}
	}
	return nil
}

// copyFile 复制文件
func copyFile(src, dst string) error {
	source, err := os.Open(src)
	if err != nil {
		return err
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	return err
}

// GetFileInfo 获取文件信息
func (s *LocalStoreService) GetFileInfo(key string) (os.FileInfo, error) {
	filePath := filepath.Join(s.rootPath, key)
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		return nil, err
	}
	return fileInfo, nil
}

// GetFileStream 获取文件流
func (s *LocalStoreService) GetFileStream(key string) (io.ReadSeeker, error) {
	filePath := filepath.Join(s.rootPath, key)
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}

	// 使用 bytes.Buffer 读取文件内容
	var buffer bytes.Buffer
	if _, err := io.Copy(&buffer, file); err != nil {
		file.Close()
		return nil, err
	}
	file.Close()

	// 使用 bytes.NewReader 创建一个支持 Seek 的 Reader
	return bytes.NewReader(buffer.Bytes()), nil
}
